/**
 * 标准ABI编码工具 - 基于pack_proof_abi_standard.js
 * 实现PLONK proof到WeBASE兼容格式的转换
 */

/**
 * 🔧 从PLONK proof.json格式提取24个uint256元素
 * PLONK证明结构：
 * - 9个G1群元素：A, B, C, Z, T1, T2, T3, Wxi, Wxiw (每个3坐标 x,y,z)
 * - 6个标量元素：eval_a, eval_b, eval_c, eval_s1, eval_s2, eval_zw
 * - 我们需要24个uint256：18个坐标(9*2) + 6个标量 = 24个
 */
export function extractProofElements(proofData: any): string[] {
    console.log('🔧 开始提取PLONK proof元素...');
    const elements: string[] = [];
    
    // PLONK proof的9个G1点，按标准顺序
    const g1Points = ['A', 'B', 'C', 'Z', 'T1', 'T2', 'T3', 'Wxi', 'Wxiw'];
    
    // 提取G1点的坐标（只取x,y，忽略z=1）
    for (const pointName of g1Points) {
        if (proofData[pointName] && Array.isArray(proofData[pointName])) {
            const point = proofData[pointName];
            if (point.length >= 2) {
                elements.push(point[0]); // x坐标
                elements.push(point[1]); // y坐标
                console.log(`   ✓ ${pointName}: [${point[0].slice(0,20)}..., ${point[1].slice(0,20)}...]`);
            } else {
                console.warn(`   ⚠️ 点 ${pointName} 坐标不足，跳过`);
            }
        } else {
            console.warn(`   ⚠️ 缺少点 ${pointName}`);
        }
    }
    
    // 添加标量字段（评估值）
    const scalarFields = ['eval_a', 'eval_b', 'eval_c', 'eval_s1', 'eval_s2', 'eval_zw'];
    for (const field of scalarFields) {
        if (proofData[field]) {
            elements.push(proofData[field]);
            console.log(`   ✓ ${field}: ${proofData[field].slice(0,20)}...`);
        } else {
            console.warn(`   ⚠️ 缺少标量 ${field}`);
        }
    }
    
    console.log(`📊 共提取了 ${elements.length} 个proof元素`);
    
    // 确保正好24个元素
    if (elements.length > 24) {
        console.log(`⚠️  截取前24个元素（原有${elements.length}个）`);
        return elements.slice(0, 24);
    } else if (elements.length < 24) {
        console.log(`⚠️  补零到24个元素（原有${elements.length}个）`);
        while (elements.length < 24) {
            elements.push('0');
        }
    }
    
    return elements;
}

/**
 * 🎯 手动实现标准ABI编码 - 完全兼容FISCO BCOS
 * 编码格式：abi.encode(uint256[24], uint256)
 * 
 * ABI编码规则：
 * 1. 固定长度数组uint256[24]：直接连续编码，每个uint256占32字节
 * 2. 单个uint256：32字节编码
 * 3. 总长度：24*32 + 32 = 800字节
 */
export function standardABIEncode(proofArray: string[], dataHash: string): string {
    console.log('🔧 执行标准ABI编码...');
    
    let encoded = '';
    
    // 第一部分：编码uint256[24]数组（768字节）
    console.log('   📝 编码proof数组 (24个uint256)...');
    for (let i = 0; i < 24; i++) {
        const element = proofArray[i] || '0';
        try {
            // 转换为BigInt确保精度，然后编码为32字节十六进制
            const bigintValue = BigInt(element);
            const hex = bigintValue.toString(16).padStart(64, '0');
            encoded += hex;
            
            if (i < 3 || i >= 21) { // 显示前3个和后3个元素
                console.log(`     [${i}]: ${element.slice(0,20)}... -> ${hex.slice(0,16)}...`);
            } else if (i === 3) {
                console.log(`     ... (显示中间元素省略) ...`);
            }
        } catch (error) {
            console.error(`❌ 编码第${i}个元素失败: ${element}`);
            throw error;
        }
    }
    
    // 第二部分：编码dataHash (32字节)
    console.log('   📝 编码dataHash...');
    try {
        const dataHashBigInt = BigInt(dataHash);
        const dataHashHex = dataHashBigInt.toString(16).padStart(64, '0');
        encoded += dataHashHex;
        console.log(`     DataHash: ${dataHash.slice(0,20)}... -> ${dataHashHex.slice(0,16)}...`);
    } catch (error) {
        console.error(`❌ 编码dataHash失败: ${dataHash}`);
        throw error;
    }
    
    const result = '0x' + encoded;
    console.log(`✅ ABI编码完成！总长度: ${result.length} 字符 (${(result.length-2)/2} 字节)`);
    
    return result;
}

/**
 * 🚀 主要编码函数 - 完整的转换流程
 * 将PLONK proof转换为WeBASE兼容的ABI编码格式
 */
export function encodeProofForWeBASE(zkProofData: any): string {
    console.log('🚀 开始PLONK proof到WeBASE格式转换...\n');
    
    try {
        // 1. 数据提取和验证
        console.log('📊 Step 1: 数据提取和验证...');
        const proofElements = extractProofElements(zkProofData.proof);
        
        // 获取dataHash (从public信号或input中)
        const dataHash = zkProofData?.input?.dataHash || zkProofData?.public?.[0] || '123456789';
        console.log(`🔢 DataHash (public signal): ${dataHash}`);
        console.log(`📋 Proof元素数量: ${proofElements.length}`);
        console.log(`📋 Proof示例 [0-2]: ${proofElements.slice(0, 3).map((e: string) => e.slice(0,15) + '...').join(', ')}`);
        
        // 2. 执行ABI编码
        console.log('\n🔧 Step 2: 执行标准ABI编码...');
        const packedProof = standardABIEncode(proofElements, dataHash);
        
        console.log('\n✅ 转换完成！');
        console.log(`📏 编码后大小: ${(packedProof.length-2)/2} 字节`);
        console.log(`🔧 编码格式: abi.encode(uint256[24], uint256)`);
        console.log(`✅ 兼容性: FISCO BCOS + WeBASE v3.1.1+`);
        
        return packedProof;
        
    } catch (error) {
        console.error(`❌ 转换失败: ${error instanceof Error ? error.message : '未知错误'}`);
        throw new Error('ABI编码失败: ' + (error instanceof Error ? error.message : '未知错误'));
    }
}

/**
 * 🔍 验证ABI编码正确性 - 确保往返编码一致
 */
export function verifyABIEncoding(packedProof: string, originalProofElements: string[], originalDataHash: string): {
    proofArrayMatch: boolean;
    dataHashMatch: boolean;
    overallSuccess: boolean;
    error?: string;
} {
    console.log('\n🔍 验证ABI编码正确性...');
    
    try {
        // 移除0x前缀
        const hexData = packedProof.slice(2);
        
        if (hexData.length !== 1600) { // 800字节 = 1600个十六进制字符
            throw new Error(`编码长度错误: 期望1600字符，实际${hexData.length}字符`);
        }
        
        // 解码proof数组（前768字节 = 24*32字节）
        console.log('   📊 解码proof数组...');
        const decodedProofElements: string[] = [];
        for (let i = 0; i < 24; i++) {
            const start = i * 64; // 每个uint256占64个十六进制字符
            const end = start + 64;
            const hexChunk = hexData.slice(start, end);
            const decodedValue = BigInt('0x' + hexChunk).toString();
            decodedProofElements.push(decodedValue);
            
            // 显示前3个和后3个元素的验证
            if (i < 3 || i >= 21) {
                const matches = decodedValue === originalProofElements[i];
                console.log(`     [${i}]: ${matches ? '✅' : '❌'} ${decodedValue.slice(0,20)}...`);
            }
        }
        
        // 解码dataHash（后32字节）
        console.log('   🔢 解码dataHash...');
        const dataHashHex = hexData.slice(24 * 64, 25 * 64);
        const decodedDataHash = BigInt('0x' + dataHashHex).toString();
        const hashMatches = decodedDataHash === originalDataHash;
        
        console.log(`     ${hashMatches ? '✅' : '❌'} DataHash: ${decodedDataHash.slice(0,30)}...`);
        
        // 全面验证
        let allProofMatches = true;
        for (let i = 0; i < 24; i++) {
            if (decodedProofElements[i] !== originalProofElements[i]) {
                console.error(`❌ Proof元素[${i}]不匹配:`);
                console.error(`   原始: ${originalProofElements[i]}`);
                console.error(`   解码: ${decodedProofElements[i]}`);
                allProofMatches = false;
            }
        }
        
        const verificationResult = {
            proofArrayMatch: allProofMatches,
            dataHashMatch: hashMatches,
            overallSuccess: allProofMatches && hashMatches
        };
        
        if (verificationResult.overallSuccess) {
            console.log('   ✅ 验证成功！编码解码完全一致');
        } else {
            console.error('   ❌ 验证失败！存在数据不匹配');
        }
        
        console.log(`   📊 解码统计: proof数组${decodedProofElements.length}元素, dataHash匹配${hashMatches}`);
        
        return verificationResult;
        
    } catch (error) {
        console.error(`❌ 验证过程出错: ${error instanceof Error ? error.message : '未知错误'}`);
        return {
            proofArrayMatch: false,
            dataHashMatch: false,
            overallSuccess: false,
            error: error instanceof Error ? error.message : '未知错误'
        };
    }
}
